package hibernate.hibernateInterface;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javassist.bytecode.Descriptor.Iterator;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Expression;

import hibernate.p.Address;
import hibernate.p.CurrencyExchange;
import hibernate.p.Pair;
import hibernate.p.Unit;

import hibernate.roomSystem.Room;
import hibernate.roomSystem.RoomState;

import hibernate.billStream.*;
import hibernate.billStream.PaymentInfo.PaymentType;

public class BillSystemHibernateInterface {

	public static List getCorpsByABBR(String abbrName,Session session)throws Exception
	{
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.abbrName = '" + abbrName+"'";

		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		return resultList;
	}
	
	public static CorporationEntity getCorpByFullName(String fullName,Session session)throws Exception
	{
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.fullName = '" + fullName+"'";

		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("CorpOverlappingException");
		CorporationEntity corp = (CorporationEntity)resultList.get(0);
		return corp;
	}
	
	public static CorporationEntity getCorpByAddress(Address address ,Session session)throws Exception
	{
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.address = '" + address+"'";

		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("CorpOverlappingException");
		CorporationEntity corp = (CorporationEntity)resultList.get(0);
		return corp;
	}
	
	public static List getCorpsByDepositeRemainder(Pair deRemainder,int compareCond,Session session)throws Exception
	{
		Double usRemainder = CurrencyExchange.currencyEx((Double)deRemainder.getFirst(), (Unit)deRemainder.getSecond());
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.depositeRemainder"+CompareCond.parseCompareScript(compareCond) + usRemainder;

		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		return resultList;
	}
	
	public static List getCorpsByUpperBoundBillPrice(Pair ubBillPrice,int compareCond,Session session)throws Exception
	{
		Double usPrice = CurrencyExchange.currencyEx((Double)ubBillPrice.getFirst(), (Unit)ubBillPrice.getSecond());
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.upperBoundBillPrice"+ CompareCond.parseCompareScript(compareCond) + usPrice;

		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		return resultList;
	}
	
	public static CorporationEntity getCorpByContact(String contact,Session session)throws Exception
	{
		String queryScript = "from CorporationEntity ce,CorpInfo ci where ce.id = ci.id and ci.contact = '" + contact+"'";
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("CorpOverlappingException");
		CorporationEntity corp = (CorporationEntity)resultList.get(0);
		return corp;
	}
	
	public static CorporationEntity getCorpByID(Long corpID,Session session)throws Exception
	{
		Criteria criteria = session.createCriteria(CorporationEntity.class);
		Criterion criterion = Expression.eq("id",corpID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("CorpOverlappingException");
		CorporationEntity corp = (CorporationEntity)resultList.get(0);
		return corp;
	}
	
	public static Bill getBillByID(Long billID,Class billClass,Session session)throws Exception
	{
		Bill bill;
		Criteria criteria = session.createCriteria(billClass);
		Criterion criterion = Expression.eq("id",billID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("BillNotFoundException");
		else if (resultList.size() > 1)
			throw new Exception("BillOverlappingException");
		if (billClass.equals(ConcreteBill.class))
			bill = (ConcreteBill)resultList.get(0);
		else
			bill = (MergedBill)resultList.get(0);
		return bill;
	}
	
	public static List getBillsByState(BillState billState,Class billClass,Session session)throws Exception
	{
		String queryScript="from "+billClass.getName()+" b where b.billState = '"+billState+"'";
		List resultList = session.createQuery(queryScript).list();
		if (resultList.size() == 0)
			throw new Exception("BillNotFoundException");
		return resultList;
	}
	
	public static List getPayedBillsByTime(Date timeFrom,Date timeTo,Session session){
		String queryScript="from ConcreteBill b where b.billState = '" +BillState.getPayed().toString()+"' and b.timePay between ? and ?";
		Query query=session.createQuery(queryScript);
		query.setDate(0,timeFrom);
		query.setDate(1,timeTo);
		return query.list();
	}
	
	public static ConcreteBill getConcreteBillByRoom(Long roomID,Session session)throws Exception
	{
		List room=session.createCriteria(Room.class).add(Expression.eq("id",roomID)).list();
		if(room.size() == 0)
			throw new Exception("room doesn't exist");
		else if(room.size() > 1) throw new Exception("unknown");
		RoomState roomState = ((Room)room.get(0)).getRoomState();
		ConcreteBill bill = roomState.getCurrentBill();
		return bill;
	}
	
	public static ExpenseRec getExpenseRecByID(Long recID,Class recClass,Session session)throws Exception
	{
		ExpenseRec expenseRec;
		Criteria criteria = session.createCriteria(recClass);
		Criterion criterion = Expression.eq("id",recID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("ExpenseRecNotFoundException");
		if (recClass.equals(ServiceRec.class))
			expenseRec = (ServiceRec)resultList.get(0);
		else
			expenseRec = (AccommodatingRec)resultList.get(0);
		return expenseRec;
	}
	
	public static Commodity getCommodityByID(Long commodityID,Class comClass,Session session)throws Exception
	{
		Commodity commodity;
		Criteria criteria = session.createCriteria(comClass);
		Criterion criterion = Expression.eq("id",commodityID);
		criteria = criteria.add(criterion);
		List resultList = criteria.list();
		if (resultList.size() == 0)
			throw new Exception("CommodityNotFoundException");
		if (comClass.equals(Service.class))
			commodity = (Service)resultList.get(0);
		else
			commodity = (Room)resultList.get(0);
		return commodity;
	}
	
	public static List getExpenseRecsByUnitNr(int unitNr,int compareCond,Session session)throws Exception
	{
		String queryScript = "from "+ServiceRec.class.getName()+" rec where rec.piece"+CompareCond.parseCompareScript(compareCond) + unitNr;
		Query query = session.createQuery(queryScript);
		List resultList = query.list();
		if (resultList.size() == 0)
			throw new Exception("CorpNotFoundException");
		return resultList;
	}
	
	public static List getAllPayedRootBill(Class retClass,Date timeFrom,Date timeTo,Session session)throws Exception{
		String queryScript = "from PaymentInfo p where p.time between ? and ?";
		Query query = session.createQuery(queryScript);
		query.setDate(0,timeFrom);
		query.setDate(1,timeTo);
		List raw=query.list();
		List ret=new LinkedList();
		
		if(raw == null || raw.size() == 0)
			throw new Exception("no bill or paymentInfo found");
		else if(retClass == PaymentInfo.class)
			return raw;
		else if(retClass != Bill.class)
			throw new IllegalArgumentException("invalid class for method: only bill or paymentInfo expected");
		
		java.util.Iterator itr=raw.iterator();
		while(itr.hasNext())
			ret.add(((PaymentInfo)((Object[])itr.next())[0]).getBill());
		return ret;
	}
	
	public static List getAllSignedBill(Class retClass,Date timeFrom,Date timeTo,Session session)throws Exception{
		String queryScript = "from PaymentInfo p where p.type='"+PaymentInfo.PaymentType.ONSIGN.toString()+
		"' and p.time between ? and ?";
		Query query = session.createQuery(queryScript);
		query.setDate(0,timeFrom);
		query.setDate(1,timeTo);
		List raw=query.list();
		List ret=new LinkedList();
		
		if(raw == null || raw.size() == 0)
			throw new Exception("no bill or paymentInfo found");
		else if(retClass == PaymentInfo.class)
			return raw;
		else if(retClass != Bill.class)
			throw new IllegalArgumentException("invalid class for method: only bill or paymentInfo expected");
		
		java.util.Iterator itr=raw.iterator();
		while(itr.hasNext())
			ret.add(((PaymentInfo)((Object[])itr.next())[0]).getBill());
		return ret;
	}
	
	public static List getAllCorpPayedBill(Class retClass,Date timeFrom,Date timeTo,Session session)throws Exception{
		String queryScript = "from PaymentInfo p where p.type='"+PaymentInfo.PaymentType.ONCORP.toString()+
		"' and p.client is null and p.corp is not null and p.time between ? and ?";
		Query query = session.createQuery(queryScript);
		query.setDate(0,timeFrom);
		query.setDate(1,timeTo);
		List raw=query.list();
		List ret=new LinkedList();
		
		if(raw == null || raw.size() == 0)
			throw new Exception("no bill or paymentInfo found");
		else if(retClass == PaymentInfo.class)
			return raw;
		else if(retClass != Bill.class)
			throw new IllegalArgumentException("invalid class for method: only bill or paymentInfo expected");
		
		java.util.Iterator itr=raw.iterator();
		while(itr.hasNext())
			ret.add(((PaymentInfo)((Object[])itr.next())[0]).getBill());
		return ret;
	}
	
	public static List getAllClientPayedBill(Class retClass,Date timeFrom,Date timeTo,Session session) throws Exception{
		String queryScript = "from PaymentInfo p where p.type = '"+PaymentInfo.PaymentType.CLIENT.toString()+
		"' and p.client is not null and p.corp is null and p.time between ? and ?";
		Query query = session.createQuery(queryScript);
		query.setDate(0,timeFrom);
		query.setDate(1,timeTo);
		List raw=query.list();
		List ret=new LinkedList();
		
		if(raw == null || raw.size() == 0)
			throw new Exception("no bill or paymentInfo found");
		else if(retClass == PaymentInfo.class)
			return raw;
		else if(retClass != Bill.class)
			throw new IllegalArgumentException("invalid class for method: only bill or paymentInfo expected");
		
		java.util.Iterator itr=raw.iterator();
		while(itr.hasNext())
			ret.add(((PaymentInfo)((Object[])itr.next())[0]).getBill());
		return ret;
	}
	
	
}
